package com.ddwl.user.service;

import cn.hutool.core.util.StrUtil;
import com.alibaba.fastjson.JSON;
import com.ddwl.common.constant.*;
import com.ddwl.common.exception.ExceptionCode;
import com.ddwl.common.exception.ParamException;
import com.ddwl.common.feign.api.GateApi;
import com.ddwl.common.feign.api.ShopApi;
import com.ddwl.common.feign.api.WalletApi;
import com.ddwl.common.service.RedisService;
import com.ddwl.common.util.*;
import com.ddwl.schema.bo.base.PageBo;
import com.ddwl.schema.bo.order.DistOrderBo;
import com.ddwl.schema.bo.user.*;
import com.ddwl.schema.vo.base.PageVo;
import com.ddwl.schema.vo.dist.UserInviteCountVo;
import com.ddwl.schema.vo.shop.ShopVo;
import com.ddwl.schema.vo.user.AgentUserInfoVo;
import com.ddwl.schema.vo.user.ShareCodeInfoVo;
import com.ddwl.schema.vo.user.UserDistInfoVo;
import com.ddwl.schema.vo.user.UserDistListVo;
import com.ddwl.schema.vo.wallet.AgentDistStatisticsDto;
import com.ddwl.user.constant.CompanyAccountEnum;
import com.ddwl.user.dao.IdentityCardDao;
import com.ddwl.user.dao.UserDao;
import com.ddwl.user.dao.UserDistStatisticalDao;
import com.ddwl.user.dao.UserStatusDao;
import com.ddwl.user.dao.dto.DistUserListQueryDto;
import com.ddwl.user.dao.dto.UserDistInfoDto;
import com.ddwl.user.dao.dto.UserInviteCountQueryDto;
import com.ddwl.user.dao.model.IdentityCard;
import com.ddwl.user.dao.model.User;
import com.ddwl.user.dao.model.UserDistStatistical;
import com.ddwl.user.dao.model.UserStatus;
import com.ddwl.user.util.InvitationCodeUtil;
import com.github.pagehelper.PageHelper;
import com.github.pagehelper.PageInfo;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.math.RoundingMode;
import java.util.*;
import java.util.function.Function;
import java.util.stream.Collectors;

/**
 * 类UserDistService.java的实现描述：用户分销信息
 *
 * @author zach
 * @Date :2020-09-01 19:16.
 */
@Service
@Slf4j
@RequiredArgsConstructor
public class UserDistService {

    private final UserDistStatisticalDao userDistStatisticalDao;
    private final UserService userService;
    private final UserDao userDao;
    private final UserStatusDao userStatusDao;
    private final RedisService redisService;
    private final IdentityCardDao identityCardDao;
    private final ProfitRegionServer profitRegionServer;
    private final GateApi gateApi;
    private final ShopApi shopApi;
    private final WalletApi walletApi;

    /**
     * 查询登录用户的下线
     *
     * @param pageBo
     * @return
     */
    public PageVo<UserDistListVo> userLower(PageBo<LowerUserDistQueryBo> pageBo) {
        String loginUserId = pageBo.getParam().getUserId();
        PageHelper.startPage(pageBo.getPage(), pageBo.getPageSize(), MySqlUtil.orderBy(pageBo.getSort(), pageBo.isAsc()));
        ParamException.isNull(pageBo.getParam(), "查询条件不能为空");
        ParamException.isNull(pageBo.getParam().getType(), "查询类型不能为空");
        DistUserListQueryDto dto = BeanConverUtils.convertBean(pageBo.getParam(), DistUserListQueryDto.class);
        switch (pageBo.getParam().getType()) {
            case "0":
                dto.setType(null);
                dto.setMasterUser(loginUserId);
                break;
            case "1":
                dto.setMasterUser(loginUserId);
                dto.setType(UserEnum.UserTypeEnum.DIST.getValue());
                break;
            case "2":
                dto.setImmediateSuperior(loginUserId);
                dto.setType(UserEnum.UserTypeEnum.DIST.getValue());
                break;
            case "3":
                dto.setIndirectSuperior(loginUserId);
                dto.setType(UserEnum.UserTypeEnum.DIST.getValue());
                break;
            case "4":
                dto.setMasterUser(loginUserId);
                dto.setType(UserEnum.UserTypeEnum.MEMBER.getValue());
                break;
            default:
                ParamException.isTrue(true, "请输入正确的查询类型");
        }
        PageInfo<UserDistInfoDto> info = new PageInfo(userDistStatisticalDao.queryDistUserList(dto));
        List<UserDistListVo> userDistListVos = getUserDistListVos(info.getList());
        return new PageVo<>(info.getTotal(),pageBo.getPage(),pageBo.getPageSize(),userDistListVos);
    }

    public UserInviteCountVo queryUserInviteCount(String userId) {
        ParamException.isTrue(StrUtil.isBlank(userId), "用户Id不能为空");
        User user = userDao.selectByPrimaryKey(userId);
        return BeanConverUtils.convertBean(userDistStatisticalDao.queryUserInviteCount(userId, user.getTopAgent()), UserInviteCountVo.class);
    }


    public UserInviteCountVo queryUserInviteCountNew(UserInviteCountQueryDto bo) {
        ParamException.isTrue(StrUtil.isBlank(bo.getUserId()), "用户Id不能为空");
        return BeanConverUtils.convertBean(userDistStatisticalDao.queryUserInviteCountNew(bo), UserInviteCountVo.class);
    }


    public List<UserInviteCountVo> queryUserInviteCountAll(UserInviteCountQueryDto bo) {
        ParamException.isTrue(CollectionUtils.isEmpty(bo.getUserIds()), "用户Id不能为空");
        return BeanConverUtils.convertBeanList(userDistStatisticalDao.queryUserInviteCountAll(bo), UserInviteCountVo.class);
    }


    /**
     * 查询用户信
     * 息
     *
     * @param pageBo
     * @return
     */
    public PageVo<UserDistListVo> userDistPage(PageBo<UserDistQueryBo> pageBo) {
        PageHelper.startPage(pageBo.getPage(), pageBo.getPageSize(), MySqlUtil.orderBy(pageBo.getSort(), pageBo.isAsc()));
        DistUserListQueryDto dto = BeanConverUtils.convertBean(pageBo.getParam(), DistUserListQueryDto.class);
        PageInfo<UserDistInfoDto> info = new PageInfo(userDistStatisticalDao.queryDistUserList(dto));
        List<UserDistInfoDto> userDistInfos = info.getList();
        PageVo<UserDistListVo> pageVo = new PageVo<>();
        pageVo.setPage(pageBo.getPage());
        pageVo.setSize(pageBo.getPageSize());
        pageVo.setTotal(info.getTotal());
        if (userDistInfos.isEmpty()) {
            pageVo.setData(new ArrayList<>());
            return pageVo;
        }
        List<String> userIds = userDistInfos.stream().map(UserDistInfoDto::getId).collect(Collectors.toList());
        Map<String, ShopVo> userShopMap = getShopVo(userIds);
        pageVo.setData(userDistInfos.stream().map(userDistInfoDto -> {
            UserDistListVo vo = BeanConverUtils.convertBean(userDistInfoDto, UserDistListVo.class);
            vo.setShop(userShopMap.get(userDistInfoDto.getId()));
            return vo;
        }).collect(Collectors.toList()));
        return pageVo;
    }

    public List<String> queryUserLowerIds(String userId) {
        List<User> users = userDao.queryUserLower(userId);
        return users.stream().map(User::getId).collect(Collectors.toList());
    }


    /**
     * 查询分销用户信息
     *
     * @param userId
     * @return
     */
    public UserDistInfoVo getUserDistById(String userId) {
        User entity = userDao.selectByPrimaryKey(userId);
        if (entity == null) {
            return null;
        }
        UserDistInfoVo vo = BeanConverUtils.convertBean(entity, UserDistInfoVo.class);
        UserStatus userStatus = userStatusDao.getUserStatus(vo.getId());
        UserDistStatistical userDistStatistical = StringUtils.hasText(entity.getMobile()) ? userDistStatisticalDao.getUserDistStatistical(vo.getId()) : userDistStatisticalDao.initUserDistStatistical(vo.getId());
        vo.setUserAuthVo(userService.getUserAuth(userId, BaseEnum.ProductEnum.FENXIAO.getName()));
        vo.setWxStatus(userStatus.getWxStatus());
        vo.setBankcardStatus(userStatus.getBankcardStatus());
        vo.setIdcardStatus(userStatus.getIdcardStatus());
        vo.setTotalAmount(userDistStatistical.getTotalAmount());
        vo.setTotalOrder(userDistStatistical.getTotalOrder());
        vo.setTotalShare(userDistStatistical.getTotalShare());
        vo.setTotalUseUser(userDistStatistical.getTotalUseUser());
        vo.setTotalCommission(userDistStatistical.getTotalCommission());
        vo.setTotalMallUseUser(userDistStatistical.getTotalMallUseUser());
        vo.setFiles(userDistStatistical.getFiles());
        IdentityCard identityCard = identityCardDao.queryUserApply(entity.getId());
        if (identityCard != null) {
            vo.setIdCardBack(identityCard.getIdCardBack());
            vo.setIdCard(identityCard.getIdCard());
            vo.setIdCardFront(identityCard.getIdCardFront());
            vo.setRegionId(identityCard.getRegionId());
            vo.setAddress(identityCard.getAdder());
        }
        return vo;
    }


    /**
     * 新增区域合伙人
     *
     * @param bo
     */
    @Transactional(rollbackFor = Exception.class)
    public void userDistAdd(UserDistRegionAddBo bo) {
        ParamException.isNotNull(userDao.queryByMobile(bo.getMobile()), ExceptionCode.MOBILE_EXISTS.getMsg());
        if (CompanyAccountEnum.COMPANY_ACCOUNT.getValue().equals(bo.getCompanyAccount())) {
            ParamException.isNotNull(userDao.queryCompanyAccount(), ExceptionCode.COMPANY_ACCOUNT_EXISTS.getMsg());
        }
        User entity = new User();
        entity.setId(UUIDGenerator.getShortUUID());
        entity.setSalt(RandomGenerateUtil.getRandomS(0, 6));
        entity.setType(UserEnum.UserTypeEnum.REGION.getValue());
        entity.setNickname(CommonUtils.mobileEncrypt(bo.getMobile()));
        entity.setRealname(bo.getRealName());
        entity.setMobile(bo.getMobile());
        entity.setProduct(BaseEnum.ProductEnum.FENXIAO.getName());
        entity.setTopAgent(entity.getId());
        entity.setRegionId(bo.getRegionId());
        entity.setCompanyAccount(bo.getCompanyAccount());
        //获取邀请码自增序列
        Long index = redisService.getValueOps().increment(RedisKey.DATA_INVITATION_INCR.getKey(), 1);
        entity.setInviteCode(InvitationCodeUtil.idToCode(index));
        String wxCode = userService.getWxaCodeUnlimitUrl(entity.getId());
        entity.setWxaCodeUnlimit(wxCode);
        userDao.insert(entity);
        UserDistStatistical userDistStatistical = UserDistStatistical.initUserDistStatistical(entity.getId());
        userDistStatistical.setFiles(bo.getFiles());
        userDistStatisticalDao.insert(userDistStatistical);
        SetUserAgentRegionBo agentRegionBo = new SetUserAgentRegionBo();
        agentRegionBo.setRegionId(Arrays.asList(bo.getRegionIds().split(Constant.DEFAULT_SEPARATOR)));
        agentRegionBo.setUserId(entity.getId());
        profitRegionServer.setUserAgentRegion(agentRegionBo);
        ParamException.isNotNull(identityCardDao.queryUserApplyByIdCard(bo.getIdCard()), "该身份证已经绑定过");
        IdentityCard identityCard = new IdentityCard();
        identityCard.setAdder(bo.getAddress());
        identityCard.setRegionId(bo.getRegionId());
        identityCard.setIdName(bo.getRealName());
        identityCard.setPhone(bo.getMobile());
        identityCard.setIdCard(bo.getIdCard());
        identityCard.setIdCardBack(bo.getIdCardBank());
        identityCard.setIdCardFront(bo.getIdCardFront());
        identityCard.setUserId(entity.getId());
        identityCard.setStatus(BaseEnum.ApplyEnum.SUCCEED.getCode());
        identityCardDao.insert(identityCard);
        UserStatus userStatus = UserStatus.initUserStatus(entity.getId());
        userStatus.setIdcardStatus(UserEnum.UserStatus.SUCCEED.getCode());
        userStatusDao.insert(userStatus);
    }

    /**
     * 用户推广数+1
     *
     * @param user
     */
    public void addPopularizeNum(UserDistStatistical user) {
        userDistStatisticalDao.addPopularizeNum(user);
    }

    public void subtractPopularizeNum(UserDistStatistical entity) {
        userDistStatisticalDao.subtractPopularizeNum(entity);
    }

    /**
     * 用户分销统计信息更新
     *
     * @param distOrderBos
     */
    public void updateUserDistStatistical(List<DistOrderBo> distOrderBos) {
        if (Objects.nonNull(distOrderBos) && !distOrderBos.isEmpty()) {
            distOrderBos.forEach((distOrderBo) -> updateUserDistStatistical(distOrderBo));
        }
    }

    private void updateUserDistStatistical(DistOrderBo distOrderBo) {
        log.info("method updateUserDistStatistical start");
        if (Objects.nonNull(distOrderBo) && StrUtil.isNotEmpty(distOrderBo.getDistUserId())) {
            log.info("DistOrderBo: {}", JSON.toJSONString(distOrderBo));
            UserDistStatistical userDistStatistical = userDistStatisticalDao.getUserDistStatistical(distOrderBo.getDistUserId());
            UserDistStatistical entity = new UserDistStatistical();
            entity.setUserId(distOrderBo.getDistUserId());
            entity.setTotalCommission(userDistStatistical.getTotalCommission().add(distOrderBo.getDistAmount()).setScale(2, RoundingMode.HALF_UP));
            if (distOrderBo.getDistType().equals(DistTypeEnum.PERSONAL.getType())) {
                entity.setTotalOrder(userDistStatistical.getTotalOrder() + 1);
                entity.setTotalAmount(userDistStatistical.getTotalAmount().add(distOrderBo.getOrderPrice()).setScale(2, RoundingMode.HALF_UP));
            }
            log.info("UserDistStatistical: {}", JSON.toJSONString(entity));
            userDistStatisticalDao.updateUserDistStatistical(entity);
        }
        log.info("method updateUserDistStatistical end");
    }

    public UserDistStatistical getUserDistStatistical(String userId) {
        return userDistStatisticalDao.getUserDistStatistical(userId);
    }

    /**
     * 升级区域经理
     *
     * @param bo
     */
    @Transactional(rollbackFor = Exception.class)
    public void upToRegionBoss(UserDistRegionAddBo bo) {
        log.info("method upToRegionBoss start");
        User mobileUser = userDao.queryByMobile(bo.getMobile());
        ParamException.isTrue(null == mobileUser || !bo.getMobile().equals(mobileUser.getMobile()), "手机号不正确");
        updateUserInfo(bo);
        updateUserDistStat(bo);
        setAgentRegion(bo);
        updateIdentityCard(bo);
        updateUserStatus(bo);
        log.info("method upToRegionBoss end");
    }

    private void updateUserStatus(UserDistRegionAddBo bo) {
        UserStatus us = userStatusDao.getUserStatus(bo.getId());
        if (null != us) {
            UserStatus userStatus = new UserStatus();
            userStatus.setId(us.getId());
            userStatus.setIdcardStatus(UserEnum.UserStatus.SUCCEED.getCode());
            userStatusDao.updateByPrimaryKeySelective(userStatus);
        } else {
            UserStatus userStatus = UserStatus.initUserStatus(bo.getId());
            userStatus.setIdcardStatus(UserEnum.UserStatus.SUCCEED.getCode());
            userStatusDao.insert(userStatus);
        }
    }

    private void updateIdentityCard(UserDistRegionAddBo bo) {
        ParamException.isNotNull(identityCardDao.queryUserApplyByIdCardNotUserId(bo.getIdCard(), bo.getId()), "该身份证好已经被绑定");
        IdentityCard identityCard = new IdentityCard();
        IdentityCard ic = identityCardDao.queryUserApply(bo.getId());
        if (null != ic) {
            identityCard.setId(ic.getId());
            fillIdentityCard(bo, identityCard);
            identityCardDao.updateByPrimaryKeySelective(identityCard);
        } else {
            fillIdentityCard(bo, identityCard);
            identityCardDao.insert(identityCard);
        }
    }

    private void fillIdentityCard(UserDistRegionAddBo bo, IdentityCard entity) {
        entity.setAdder(bo.getAddress());
        entity.setRegionId(bo.getRegionId());
        entity.setIdName(bo.getRealName());
        entity.setPhone(bo.getMobile());
        entity.setIdCard(bo.getIdCard());
        entity.setIdCardBack(bo.getIdCardBank());
        entity.setIdCardFront(bo.getIdCardFront());
        entity.setUserId(bo.getId());
        entity.setStatus(BaseEnum.ApplyEnum.SUCCEED.getCode());
    }

    private void setAgentRegion(UserDistRegionAddBo bo) {
        SetUserAgentRegionBo agentRegionBo = new SetUserAgentRegionBo();
        agentRegionBo.setRegionId(Arrays.asList(bo.getRegionIds().split(Constant.DEFAULT_SEPARATOR)));
        agentRegionBo.setUserId(bo.getId());
        profitRegionServer.setUserAgentRegion(agentRegionBo);
    }

    private void updateUserInfo(UserDistRegionAddBo bo) {
        UserDistInfoVo vo = getUserDistById(bo.getId());
        log.info("UserDistInfoVo: {}", JSON.toJSONString(vo));
        User entity = new User();
        entity.setId(vo.getId());
        entity.setType(UserEnum.UserTypeEnum.REGION.getValue());
        entity.setTopAgent(vo.getId());
        entity.setRealname(bo.getRealName());
        entity.setRegionId(bo.getRegionId());
        entity.setAgentRegion(bo.getRegionIds());
        userService.upToReionBoss(entity);
    }

    private void updateUserDistStat(UserDistRegionAddBo bo) {
        UserDistStatistical userDistStatistical = userDistStatisticalDao.getUserDistStatistical(bo.getId());
        log.info("UserDistInfoVo: {}", JSON.toJSONString(userDistStatistical));
        UserDistStatistical uds = new UserDistStatistical();
        uds.setId(userDistStatistical.getId());
        uds.setFiles(bo.getFiles());
        userDistStatisticalDao.updateByPrimaryKeySelective(uds);
    }

    public void updatePopularizeNum(UserDistStatistical entity) {
        userDistStatisticalDao.updateByPrimaryKeySelective(entity);
    }

    public String getUserShareCode(String userId) {
        ShopVo vo = shopApi.getSimpleShopByUserId(userId).getResult();
        String shopId = null;
        if (null != vo) {
            shopId = vo.getId();
        }
        saveShareCodeInfoToRedis(shopId, userId);
        return gateApi.getUserShareCode(userId, BaseEnum.WxAppId.WBM.getCode()).getResult();
    }

    private void saveShareCodeInfoToRedis(String shopId, String userId) {
        ShareCodeInfoVo sciVo = new ShareCodeInfoVo();
        sciVo.setShopId(shopId);
        sciVo.setShareUserId(userId);
        redisService.getValueOps().set(RedisKey.SHARE_CODE_INFO.getKey(userId), JSON.toJSONString(sciVo));
    }

    public ShareCodeInfoVo getShareCodeInfo(String scene) {
        String info = redisService.getValueOps().get(RedisKey.SHARE_CODE_INFO.getKey(scene));
        if (!StringUtils.hasText(info)) {
            return null;
        }
        ShareCodeInfoVo vo = JSON.parseObject(info, ShareCodeInfoVo.class);
        if (!StringUtils.hasText(vo.getShareUserId())) {
            ShopVo shopVo = shopApi.getShopById(vo.getShopId()).getResult();
            if (shopVo != null) {
                vo.setShareUserId(shopVo.getUserId());
            }
        }
        return vo;
    }

    public PageVo<AgentUserInfoVo> subAgent(PageBo<UserAgentQueryBo> pageBo) {
        UserAgentQueryBo bo = pageBo.getParam();
        PageHelper.startPage(pageBo.getPage(), pageBo.getPageSize(), MySqlUtil.orderBy(pageBo.getSort(), pageBo.isAsc()));
        PageInfo<User> info = new PageInfo(userService.selectSubAgentUser(bo));
        List<AgentUserInfoVo> listVos = new ArrayList<>();
        if (!info.getList().isEmpty()) {
            List<User> users = info.getList();
            listVos = BeanConverUtils.convertBeanList(users, AgentUserInfoVo.class);
            List<String> userIds = listVos.stream().map(AgentUserInfoVo::getId).collect(Collectors.toList());
            setDistAmount(bo.getUserId(), listVos, userIds);
            //setShopInfo(listVos,userIds); 如果需要店铺信息放开注释
        }
        return new PageVo<>(info.getTotal(), pageBo.getPage(), pageBo.getPageSize(), listVos);
    }

    private void setDistAmount(String userId, List<AgentUserInfoVo> listVos, List<String> sources) {
        List<AgentDistStatisticsDto> distList=walletApi.getAgentDistStatistics(userId,sources).getResult();
        if (!CollectionUtils.isEmpty(distList)) {
            listVos.forEach(agent -> {
                AgentDistStatisticsDto agentDistStatisticsDto = distList.stream().filter(dto -> dto.getSource().equals(agent.getId())).findFirst().orElse(null);
                if (null != agentDistStatisticsDto) {
                    agent.setToSuperiorAmount(agentDistStatisticsDto.getDistAmount());
                }
            });
        }
    }

    private void setShopInfo(List<AgentUserInfoVo> listVos,List<String> userIds) {
        Map<String, ShopVo> userShopMap = getShopVo(userIds);
        listVos.forEach(agent ->{
            agent.setShop(userShopMap.get(agent.getId()));
        });
    }

    private List<UserDistListVo> getUserDistListVos(List<UserDistInfoDto> userDistInfos) {
        List<UserDistListVo> listVos = new ArrayList<>();
        if (!userDistInfos.isEmpty()) {
            List<String> userIds = userDistInfos.stream().map(UserDistInfoDto::getId).collect(Collectors.toList());
            Map<String, ShopVo> userShopMap = getShopVo(userIds);
            listVos = userDistInfos.stream().map(userDistInfoDto -> {
                UserDistListVo vo = BeanConverUtils.convertBean(userDistInfoDto, UserDistListVo.class);
                vo.setShop(userShopMap.get(userDistInfoDto.getId()));
                return vo;
            }).collect(Collectors.toList());
        }
        return listVos;
    }

    private Map<String, ShopVo> getShopVo(List<String> userIds) {
        List<ShopVo> shops = shopApi.getSimpleShopByUserIds(userIds).getResult();
        return shops.stream().collect(Collectors.toMap(ShopVo::getUserId, Function.identity(), (k1, k2) -> k1));
    }
}
